package com.cskaoyan.mall.payment.controller;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.cskaoyan.mall.common.constant.RedisConst;
import com.cskaoyan.mall.common.result.Result;
import com.cskaoyan.mall.order.dto.OrderInfoDTO;
import com.cskaoyan.mall.pay.api.dto.PaymentInfoDTO;
import com.cskaoyan.mall.payment.alipay.CsmallAlipayConfig;
import com.cskaoyan.mall.payment.alipay.factory.PayHelperFactory;
import com.cskaoyan.mall.payment.client.OrderApiClient;
import com.cskaoyan.mall.payment.constant.PaymentType;
import com.cskaoyan.mall.payment.service.PayService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author Macro_Ray
 * @since 2024/6/25 下午2:33
 */
@Slf4j
@Controller
@RequestMapping("/pay")
public class PayController {

    @Autowired
    PayService payService;
    @Autowired
    OrderApiClient orderApiClient;
    @Autowired
    CsmallAlipayConfig alipayConfig;
    @Autowired
    RedissonClient redissonClient;

    /**
     * 支付页面
     */
    @GetMapping("/auth")
    @ResponseBody
    public Result<OrderInfoDTO> payIndex(Long orderId) {
        log.info("enter {} for {}", PayController.class.getSimpleName(), "index");
        OrderInfoDTO orderInfoDTO = orderApiClient.getOrderInfoDTO(orderId);
        log.info("before render template {} for {}", "payment/pay", "payIndex");
        return Result.ok(orderInfoDTO);
    }

    /**
     * 支付宝支付，获取支付表单
     */
    @GetMapping("/alipay/submit/{orderId}")
    @ResponseBody
    public String submitOrder(@PathVariable Long orderId) {
        return payService.createAliPay(orderId);
    }

    /**
     * 支付成功：同步回调，重定向页面
     */
    @GetMapping("/alipay/callback/return")
    public String callBack() {
        log.info("支付成功，同步回调！");
        // getReturnOrderUrl()  返回重定向响应
        return "redirect:" + alipayConfig.getReturnOrderUrl();
    }

    /**
     * 支付成功：异步回调
     */
    @PostMapping("/alipay/callback/notify")
    @ResponseBody
    @SneakyThrows
    public String callbackNotify(@RequestParam Map<String, String> paramsMap) {
        // 验签
        boolean checkNotifyResult = checkNotify(paramsMap);
        if (!checkNotifyResult) return "failure";

        // 判断通知是否重复
        boolean isDuplicate = checkNotifyDuplication(paramsMap);
        if (isDuplicate) {
            // 接收到了重复的通知
            return "success";
        }
        // 执行业务逻辑
        String outTradeNo = paramsMap.get("out_trade_no");
        // todo  outTradeNo如果是唯一标识，为什么要传支付类型 -- 因为用户在 点击支付但未完成支付 时就创建了支付信息，此时用户可以更改支付方式
        Boolean isSuccess = payService.successPay(outTradeNo, PaymentType.ALIPAY.name(), paramsMap);
        // 业务逻辑成功
        if (isSuccess) {
            return "success";
        }
        // 业务逻辑失败
        return "failure";
    }

    /**
     * .01 检验参数
     */
    private boolean checkNotify(Map<String, String> paramsMap) throws AlipayApiException {
        // 校验数字签名
        boolean signVerified
                = AlipaySignature.rsaCheckV1(paramsMap, alipayConfig.getAlipayPublicKey(), CsmallAlipayConfig.CHARSET,
                CsmallAlipayConfig.SIGN_TYPE);
        if (!signVerified) {
            return false;
        }

        // 获取业务校验参数
        // 订单的唯一标识
        String out_trade_no = paramsMap.get("out_trade_no");
        String total_amount = paramsMap.get("total_amount");
        String app_id = paramsMap.get("app_id");
        String tradeStatus = paramsMap.get("trade_status");
        if (!alipayConfig.getAppId().equals(app_id)) {
            // 不是给我们的请求
            return false;
        }
        // 校验订单参数
        PaymentInfoDTO paymentInfoDTO
                = payService.queryPaymentInfoByOutTradeNoAndPaymentType(out_trade_no, PaymentType.ALIPAY.name());
        if (paymentInfoDTO == null) {
            // 没查询出支付信息
            return false;
        }

        if (Double.compare(Double.parseDouble(total_amount)
                , paymentInfoDTO.getTotalAmount().doubleValue()) != 0) {
            // 金额不对
            return false;
        }

        if (tradeStatus == null || ((!"TRADE_SUCCESS".equals(tradeStatus)) && (!"TRADE_FINISHED".equals(tradeStatus)))) {
            // 交易状态不对
            return false;
        }

        // 返回true说明通过了数字签名和数据校验
        return true;
    }

    /**
     * .02 验证是否重复通知
     */
    private boolean checkNotifyDuplication(Map<String, String> paramsMap) {
        String notifyId = paramsMap.get("notify_id");
        // 幂等性校验
        RBucket<String> bucket
                = redissonClient.getBucket(RedisConst.PAY_CALL_BACK_VERFY_PREFIX + notifyId);
        // setnx
        boolean isSuccess = bucket.trySet(notifyId, 25, TimeUnit.HOURS);
        // 表示重复的通知，返回success
        if (!isSuccess) return true;

        // 不是重复的通知
        return false;
    }
}
